/*
 * Copyright 2014 Semidata. All rights reserved.
 */
package com.semidata.trp.report.data;

import java.util.HashMap;
import java.util.Map;
import com.semidata.trp.report.utils.SqlUtils;

/**
 * @author shewei@semidata.com, She Wei
 * 
 */
public class ReportData {

	private ReportEntity total = new ReportEntity();
	private Map<Integer, ReportEntity> media = new HashMap<>();
	private Map<Integer, ReportEntity> org = new HashMap<>();
	private Map<Integer, ReportEntity> type = new HashMap<>();
	private Map<Integer, ReportEntity> resource = new HashMap<>();
	private Map<Integer, ReportEntity> strategy = new HashMap<>();
	private Map<Integer, ReportEntity> position = new HashMap<>();
	private Map<Integer, Map<Integer, ReportEntity>> orgPosition = new HashMap<>();
	private Map<Integer, Map<Integer, ReportEntity>> orgType = new HashMap<>();
	private Map<Integer, Map<Integer, ReportEntity>> orgMedia = new HashMap<>();
	private Map<Integer, Map<Integer, ReportEntity>> strategyPosition = new HashMap<>();
	private Map<Integer, Map<Integer, ReportEntity>> strategyType = new HashMap<>();
	private Map<Integer, Map<Integer, ReportEntity>> strategyResource = new HashMap<>();

	public String toString() {
		StringBuffer sb = new StringBuffer();

		sb.append("total\t").append(total.toString()).append('\n');

		sb.append("media\t");
		for (Map.Entry<Integer, ReportEntity> entry : media.entrySet()) {
			sb.append(entry.getKey()).append(':')
			        .append(entry.getValue().toString());
		}
		sb.append('\n');

		sb.append("position\t");
		for (Map.Entry<Integer, ReportEntity> entry : position.entrySet()) {
			sb.append(entry.getKey()).append(':')
			        .append(entry.getValue().toString());
		}
		sb.append('\n');

		sb.append("resource\t");
		for (Map.Entry<Integer, ReportEntity> entry : resource.entrySet()) {
			sb.append(entry.getKey()).append(':')
			        .append(entry.getValue().toString());
		}
		sb.append('\n');

		sb.append("type\t");
		for (Map.Entry<Integer, ReportEntity> entry : type.entrySet()) {
			sb.append(entry.getKey()).append(':')
			        .append(entry.getValue().toString());
		}
		sb.append('\n');

		sb.append("org\t");
		for (Map.Entry<Integer, ReportEntity> entry : org.entrySet()) {
			sb.append(entry.getKey()).append(':')
			        .append(entry.getValue().toString());
		}
		sb.append('\n');

		sb.append("strategy\t");
		for (Map.Entry<Integer, ReportEntity> entry : strategy.entrySet()) {
			sb.append(entry.getKey()).append(':')
			        .append(entry.getValue().toString());
		}
		sb.append('\n');

		sb.append("orgMedia\t");
		for (Map.Entry<Integer, Map<Integer, ReportEntity>> orgEntry : orgMedia
		        .entrySet()) {
			Integer orgId = orgEntry.getKey();
			for (Map.Entry<Integer, ReportEntity> entry : orgEntry.getValue()
			        .entrySet()) {
				sb.append(orgId).append(':').append(entry.getKey()).append(':')
				        .append(entry.getValue().toString());
			}
		}
		sb.append('\n');

		sb.append("orgPosition\t");
		for (Map.Entry<Integer, Map<Integer, ReportEntity>> orgEntry : orgPosition
		        .entrySet()) {
			Integer orgId = orgEntry.getKey();
			for (Map.Entry<Integer, ReportEntity> entry : orgEntry.getValue()
			        .entrySet()) {
				sb.append(orgId).append(':').append(entry.getKey()).append(':')
				        .append(entry.getValue().toString());
			}
		}
		sb.append('\n');

		sb.append("orgType\t");
		for (Map.Entry<Integer, Map<Integer, ReportEntity>> orgEntry : orgType
		        .entrySet()) {
			Integer orgId = orgEntry.getKey();
			for (Map.Entry<Integer, ReportEntity> entry : orgEntry.getValue()
			        .entrySet()) {
				sb.append(orgId).append(':').append(entry.getKey()).append(':')
				        .append(entry.getValue().toString());
			}
		}
		sb.append('\n');

		sb.append("strategyResource\t");
		for (Map.Entry<Integer, Map<Integer, ReportEntity>> strategyEntry : strategyResource
		        .entrySet()) {
			Integer strategyId = strategyEntry.getKey();
			for (Map.Entry<Integer, ReportEntity> entry : strategyEntry
			        .getValue().entrySet()) {
				sb.append(strategyId).append(':').append(entry.getKey())
				        .append(':').append(entry.getValue().toString());
			}
		}
		sb.append('\n');

		sb.append("strategyPosition\t");
		for (Map.Entry<Integer, Map<Integer, ReportEntity>> strategyEntry : strategyPosition
		        .entrySet()) {
			Integer strategyId = strategyEntry.getKey();
			for (Map.Entry<Integer, ReportEntity> entry : strategyEntry
			        .getValue().entrySet()) {
				sb.append(strategyId).append(':').append(entry.getKey())
				        .append(':').append(entry.getValue().toString());
			}
		}
		sb.append('\n');

		sb.append("strategyType\t");
		for (Map.Entry<Integer, Map<Integer, ReportEntity>> strategyEntry : strategyType
		        .entrySet()) {
			Integer strategyId = strategyEntry.getKey();
			for (Map.Entry<Integer, ReportEntity> entry : strategyEntry
			        .getValue().entrySet()) {
				sb.append(strategyId).append(':').append(entry.getKey())
				        .append(':').append(entry.getValue().toString());
			}
		}
		sb.append('\n');
		return sb.toString();
	}

	public void merge(ReportData data) {

		total.merge(data.total);
		mergeMap(media, data.media);
		mergeMap(org, data.org);
		mergeMap(type, data.type);
		mergeMap(resource, data.resource);
		mergeMap(strategy, data.strategy);
		mergeMap(position, data.position);
		mergeComplexMap(orgPosition, data.orgPosition);
		mergeComplexMap(orgType, data.orgType);
		mergeComplexMap(orgMedia, data.orgMedia);
		mergeComplexMap(strategyPosition, data.strategyPosition);
		mergeComplexMap(strategyType, data.strategyType);
		mergeComplexMap(strategyResource, data.strategyResource);
	}

	private void mergeComplexMap(Map<Integer, Map<Integer, ReportEntity>> base,
	        Map<Integer, Map<Integer, ReportEntity>> map) {

		for (Map.Entry<Integer, Map<Integer, ReportEntity>> entry : map
		        .entrySet()) {

			Map<Integer, ReportEntity> m = base.get(entry.getKey());
			if (m == null) {
				base.put(entry.getKey(), entry.getValue());
			} else {
				mergeMap(m, entry.getValue());
			}
		}
	}

	private void mergeMap(Map<Integer, ReportEntity> base,
	        Map<Integer, ReportEntity> map) {
		for (Map.Entry<Integer, ReportEntity> entry : map.entrySet()) {

			ReportEntity entity = base.get(entry.getKey());
			if (entity == null) {
				base.put(entry.getKey(), entry.getValue());
			} else {
				entity.merge(entry.getValue());
			}
		}
	}

	private void addUserReport(Map<Integer, ReportEntity> map, int id, int pv,
	        int click, double cost) {

		ReportEntity entity = map.get(id);
		if (entity == null) {
			entity = new ReportEntity();
			entity.setPv(pv);
			entity.setUv(1);
			entity.setClick(click);
			entity.setCost(cost);
			map.put(id, entity);
		} else {
			entity.increasePv(pv);
			entity.increaseClick(click);
			entity.increaseCost(cost);
		}
	}

	private void addUserReport(Map<Integer, Map<Integer, ReportEntity>> map,
	        int id1, int id2, int pv, int click, double cost) {
		Map<Integer, ReportEntity> subMap = map.get(id1);
		if (subMap == null) {
			subMap = new HashMap<>();
			map.put(id1, subMap);
		}

		addUserReport(subMap, id2, pv, click, cost);
	}

	public void merge(UserData data,
	        Map<String, Map<Integer, Integer>> businessMap) {

		Map<Integer, Integer> positionMap = businessMap.get("position");
		Map<Integer, Integer> mediaMap = businessMap.get("media");
		Map<Integer, Integer> orgMap = businessMap.get("org");
		Map<Integer, Integer> typeMap = businessMap.get("type");

		Map<Integer, Map<Integer, UserReport>> dataMap = data.getDataMap();

		int totalPv = 0;
		int totalClick = 0;
		double totalCost = 0;

		boolean flag = false;

		Map<Integer, ReportEntity> mediaEntityMap = new HashMap<>();
		Map<Integer, ReportEntity> positionEntityMap = new HashMap<>();
		Map<Integer, ReportEntity> resourceEntityMap = new HashMap<>();
		Map<Integer, ReportEntity> typeEntityMap = new HashMap<>();
		Map<Integer, ReportEntity> strategyEntityMap = new HashMap<>();
		Map<Integer, ReportEntity> orgEntityMap = new HashMap<>();
		Map<Integer, Map<Integer, ReportEntity>> orgPositionEntityMap = new HashMap<>();
		Map<Integer, Map<Integer, ReportEntity>> orgTypeEntityMap = new HashMap<>();
		Map<Integer, Map<Integer, ReportEntity>> orgMediaEntityMap = new HashMap<>();
		Map<Integer, Map<Integer, ReportEntity>> strategyPositionEntityMap = new HashMap<>();
		Map<Integer, Map<Integer, ReportEntity>> strategyTypeEntityMap = new HashMap<>();
		Map<Integer, Map<Integer, ReportEntity>> strategyResourceEntityMap = new HashMap<>();

		for (Map.Entry<Integer, Map<Integer, UserReport>> resourceEntry : dataMap
		        .entrySet()) {

			int resourceId = resourceEntry.getKey();
			Integer positionId = positionMap.get(resourceId);
			Integer mediaId = mediaMap.get(resourceId);
			Integer typeId = typeMap.get(resourceId);

			if (positionId == null || mediaId == null || typeId == null)
				continue;

			for (Map.Entry<Integer, UserReport> strategyEntry : resourceEntry
			        .getValue().entrySet()) {

				int strategyId = strategyEntry.getKey();
				Integer orgId = orgMap.get(strategyId);
				if (orgId == null)
					continue;
				flag = true;

				int pv = strategyEntry.getValue().getImpression();
				int click = strategyEntry.getValue().getClick();
				double cost = strategyEntry.getValue().getCost() / 1000000.0;

				totalPv += pv;
				totalClick += click;
				totalCost += cost;

				addUserReport(mediaEntityMap, mediaId, pv, click, cost);
				addUserReport(typeEntityMap, typeId, pv, click, cost);
				addUserReport(resourceEntityMap, resourceId, pv, click, cost);
				addUserReport(positionEntityMap, positionId, pv, click, cost);
				addUserReport(strategyEntityMap, strategyId, pv, click, cost);
				addUserReport(orgEntityMap, orgId, pv, click, cost);
				addUserReport(orgPositionEntityMap, orgId, positionId, pv,
				        click, cost);
				addUserReport(orgTypeEntityMap, orgId, typeId, pv, click, cost);
				addUserReport(orgMediaEntityMap, orgId, mediaId, pv, click,
				        cost);
				addUserReport(strategyPositionEntityMap, strategyId,
				        positionId, pv, click, cost);
				addUserReport(strategyTypeEntityMap, strategyId, typeId, pv,
				        click, cost);
				addUserReport(strategyResourceEntityMap, strategyId,
				        resourceId, pv, click, cost);
			}
		}

		if (flag) {
			total.increasePv(totalPv);
			total.increaseUv(1);
			total.increaseClick(totalClick);
			total.increaseCost(totalCost);
			
			mergeMap(media, mediaEntityMap);
			mergeMap(org, orgEntityMap);
			mergeMap(type, typeEntityMap);
			mergeMap(resource, resourceEntityMap);
			mergeMap(strategy, strategyEntityMap);
			mergeMap(position, positionEntityMap);
			mergeComplexMap(orgPosition, orgPositionEntityMap);
			mergeComplexMap(orgType, orgTypeEntityMap);
			mergeComplexMap(orgMedia, orgMediaEntityMap);
			mergeComplexMap(strategyPosition, strategyPositionEntityMap);
			mergeComplexMap(strategyType, strategyTypeEntityMap);
			mergeComplexMap(strategyResource, strategyResourceEntityMap);

		}
	}

	public static void main(String[] args) {

		ReportData data = new ReportData();

		Map<String, Map<Integer, Integer>> businessMap = SqlUtils
		        .getBusinessMap();

		UserData userData = new UserData();
		userData.add(1, 1, 1, 1, 1);
		userData.add(1, 2, 1, 1, 1);
		userData.add(1, 3, 1, 1, 1);
		userData.add(2, 1, 1, 1, 1);
		userData.add(2, 2, 1, 1, 1);
		userData.add(2, 3, 1, 1, 1);
		data.merge(userData, businessMap);

		System.out.println(data);
	}

	public ReportEntity getTotal() {
		// TODO Auto-generated method stub
		return total;
	}

	public Map<Integer, ReportEntity> getMedia() {
		// TODO Auto-generated method stub
		return media;
	}
	
	public Map<Integer, ReportEntity> getOrg() {
		return org;
	}

	public Map<Integer, ReportEntity> getType() {
		return type;
	}

	public Map<Integer, ReportEntity> getResource() {
		return resource;
	}

	public Map<Integer, ReportEntity> getStrategy() {
		return strategy;
	}

	public Map<Integer, ReportEntity> getPosition() {
		return position;
	}

	public Map<Integer, Map<Integer, ReportEntity>> getOrgPosition() {
		return orgPosition;
	}

	public Map<Integer, Map<Integer, ReportEntity>> getOrgType() {
		return orgType;
	}

	public Map<Integer, Map<Integer, ReportEntity>> getOrgMedia() {
		return orgMedia;
	}

	public Map<Integer, Map<Integer, ReportEntity>> getStrategyPosition() {
		return strategyPosition;
	}

	public Map<Integer, Map<Integer, ReportEntity>> getStrategyType() {
		return strategyType;
	}

	public Map<Integer, Map<Integer, ReportEntity>> getStrategyResource() {
		return strategyResource;
	}

}
